#include <unistd.h>
#include <string>
#include <iostream>
#include <vector>
#include "task.hpp"

using namespace std;

enum{
    UsageError = 1,
    ArgError,
    PipeError
};

class Channel
{
public:
    Channel(int wfd,pid_t sub_id,const string&name)
        :_wfd(wfd),_sub_process_id(sub_id),_name(name)
        {}
    void PrintDebug()
    {
        cout<<"_wfd?:"<<_wfd;
        cout<<",_sub_process_id:"<<_sub_process_id;
        cout<<",_name:"<<_name<<endl;
    }
    string getName()
    {
        return _name;
    }
    int getWfd()
    {
        return _wfd;
    }
    pid_t getId()
    {
        return _sub_process_id;
    }
    ~Channel(){}
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
    
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
        : _sub_process_num(sub_process_num)
        {}
    int CreateProcess(work_t work)
    {
        for(int number = 0;number<_sub_process_num;++number)
        {
            int pipefd[0]{};
            int n = pipe(pipefd);
            if(n<0)
            {
                return PipeError;
            }
            pid_t id = fork();
            if(id == 0)
            {
                //child r
                close(pipefd[1]);
                dup2(pipefd[0],0);
                work();
                exit(0);
            }
            //father
            string cname = "channel-"+to_string(number);
            close(pipefd[0]);
            channels.push_back(Channel(pipefd[1],id,cname));
        }
        return 0;
    }
    int NextChannel()
    {
        static int next = 0;
        int c = next;
        next++;
        next%=channels.size();
        return c;
    }
    void SendTaskCode(int index,uint32_t code)
    {
        cout<<"send code:"<<code<<" to "<<channels[index].getName()<<" sub process id:"<<channels[index].getId()<<endl;
        write(channels[index].getWfd(),&code,sizeof(code)); 
    }

    void Debug()
    {
        for(auto& channel:channels)
        {
            channel.PrintDebug();
        }
    }
    ~ProcessPool(){}
private:
    int _sub_process_num;
    vector<Channel> channels;
};

void Usage(const char* proc)
{
    cout<<"Usage:"<<proc<<" subprocess-num"<<endl;
}

int main(int argc,char* argv[])
{
    /**
     * :paranm argc:数组argc元素的个数
     * :paranm argv:存放执行可执行文件时的参数
     */
    if(argc!=2)
    {
        //提示用法
        Usage(argv[0]);
        return UsageError;
    }
    //创建子进程的数量
    int sub_process_num = stoi(argv[1]);
    if(sub_process_num<=0)
    {
        return ArgError;
    }
    ProcessPool* processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker);
    while(true)
    {
        int channel = processpool_ptr->NextChannel();
        uint32_t code = NextTask();
        processpool_ptr->SendTaskCode(channel,code);
        sleep(1);
    }
    sleep(100);
    delete processpool_ptr;
    

    return 0;
}